package gitobject;

import utility.Utility;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.security.MessageDigest;
import java.util.ArrayList;

public class Tree extends GitObject {
    ArrayList<GitObject> objectTree = new ArrayList<>();
    Path path;

    public Tree() {
        type = Type.Tree;
    }

    /**
     * @return 获取Tree类对象的objectTree
     */
    public ArrayList<GitObject> getObjectTree() {
        return objectTree;
    }

    /**
     * @return 根据Tree类的结构特点，递归获取Tree对象的哈希值
     */
    @Override
    public byte[] getKey() {
        // 当列表变化时，key值会被清空，此时需要重新计算
        if (key == null) {
            try {
                MessageDigest md = MessageDigest.getInstance("SHA-1");
                md.update(path.toString().getBytes(StandardCharsets.UTF_8));
                for (GitObject object : objectTree) {
                    md.update(object.getKey());
                }
                key = md.digest();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return key;
    }

    /**
     * 向Tree类对象中添加一个GitObject类对象
     *
     * @param object 要添加的GitObject类对象
     */
    public void add(GitObject object) {
        key = null;
        objectTree.add(object);
    }

    /**
     * 为Tree类对象的path赋值
     *
     * @param path
     */
    public void setPath(Path path) {
        this.path = path;
    }

    /**
     * 对Tree类对象写入额外信息
     *
     * @param out
     * @throws IOException
     */
    @Override
    public void writeExtendInfo(DataOutputStream out) throws IOException {
        out.writeUTF(path.toString());
        out.writeInt(objectTree.size());
        for (var obj : objectTree) {
            out.write(obj.key, 0, 20);
        }
    }

    /**
     * 从Tree类对象读取额外信息
     *
     * @param in
     * @throws IOException
     */
    @Override
    public void readExtendInfo(DataInputStream in) throws IOException {
        path = Path.of(in.readUTF());
        int count = in.readInt();
        objectTree.ensureCapacity(count);
        byte[] obj_key = new byte[20];
        for (int i = 0; i < count; i++) {
            int n = in.read(obj_key, 0, 20);
            assert n == 20;
            objectTree.add(
                    GitObject.findByKey(Utility.hex2string(obj_key))
            );
        }
    }

    /**
     * 在目标路径下恢复Tree文件内容
     *
     * @param prefix 目标路径
     * @throws IOException
     */
    @Override
    public void restoreContent(Path prefix) throws IOException {
        Path realPath = prefix.resolve(path);
        assert realPath.toFile().mkdirs();
        for (var obj : objectTree) {
            obj.restoreContent(prefix);
        }
    }

    /**
     * 向Tree类对象的objectTree中每个GitObject对象的仓库暂存区文件中写入内容
     *
     * @throws IOException
     */
    @Override
    public void write() throws IOException {
        super.write();
        for (var obj : objectTree) {
            obj.write();
        }
    }
}
